package cn.com.header.zbpk.sys.controller;
import cn.com.header.zbpk.account.service.IUserService;
import cn.com.header.zbpk.sys.model.HttpSessionConfigurator;
import com.google.common.collect.Lists;
import net.sf.json.JSONObject;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value="/sys/websocket",  configurator = HttpSessionConfigurator.class)
public class MyWebSocket {

    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    private HttpSession httpSession;

    public HttpSession getHttpSession() {
        return httpSession;
    }

    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key可以为用户标识
    private static CopyOnWriteArrayList<MyWebSocket> webSocketList = new CopyOnWriteArrayList<MyWebSocket>();
    private static Map<String,MyWebSocket> webSocketMap= new ConcurrentHashMap<>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    private String name;
    /**
     * 连接建立成功调用的方法
     * @param session  可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session,EndpointConfig config){


        HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());

        IUserService.SecurityUser user = (IUserService.SecurityUser) httpSession.getAttribute("sessionUser");
        if(user != null){
            this.session = session;
            this.httpSession = httpSession;
            this.name=user.getName();
            webSocketList.add(this);     //加入List中
            //在线数加1

            addOnlineCount(httpSession.getId(),this);
            System.out.println("有一连接开始！当前在线人数为" + getOnlineCount());
        }else{
            //用户未登陆
            try {
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        String sessionId=this.httpSession.getId();
        subOnlineCount(sessionId);           //在线数减1
        webSocketList.remove(this);  //从set中删除
        System.out.println("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + message);
        for(MyWebSocket item: webSocketList){
            try {
                JSONObject obj=new JSONObject();
                System.out.println(message.contains("\\n"));
               // message.replaceAll("\\n","<br>");
                obj.put("userName",this.name);
                obj.put("message",message);
                item.sendMessage(obj.toString());
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
    }

    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("发生错误");
        error.printStackTrace();
    }

    /**
     * 这个方法与上面几个方法不一样。没有用注解，是根据自己需要添加的方法。
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException{
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount(String sessionId,MyWebSocket webSocket) {
        if(!webSocketMap.containsKey(sessionId)){
            webSocketMap.put(sessionId,webSocket);
            MyWebSocket.onlineCount++;
        }

    }

    public static synchronized void subOnlineCount(String sessionId) {
        List<MyWebSocket> list=webSocketList.stream().filter(socket->socket.httpSession.getId().equals(sessionId)).collect(Collectors.toList());
        if(list.size()==1){
            MyWebSocket.onlineCount--;
            webSocketMap.remove(sessionId);
        }
    }

}